package com.auth.sdk.auth;

import com.auth.sdk.transmit.LoginContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Component
public class DefaultAuthProcess implements IAuth {

    private String msg = "权限不足";
    private String msg1 = "权限不足, 需要角色（or）: {}";
    private String msg2 = "权限不足, 需要角色（and）: {}";
    private String msg3 = "权限不足, 需要权限（or）: {}";
    private String msg4 = "权限不足, 需要权限（and）: {}";

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public void auth(ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        Roles roles = method.getAnnotation(Roles.class);
        Auths auths = method.getAnnotation(Auths.class);
        if (null == roles && null == auths) {
            return;
        }

        if (null != roles) {
            String[] and = roles.and();
            String[] or = roles.or();
            this.checkRoleAnd(and);
            this.checkRoleOr(or);
        }
        if (null != auths) {
            String[] and1 = auths.and();
            String[] or1 = auths.or();
            this.checkAuthAnd(and1);
            this.checkAuthOr(or1);
        }


    }

    private void checkAuthOr(String[] or1) {
        List<String> need = Arrays.asList(or1).stream().distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(need)) {
            return;
        }
        List<Object> loginAuths = LoginContextHolder.getLoginAuths().stream().distinct().collect(Collectors.toList());
        loginAuths.retainAll(need);
        if (loginAuths.size() <= 0) {
            log.warn(msg3, need);
            throw new RuntimeException(msg);
        }
    }

    private void checkRoleOr(String[] or) {
        List<String> need = Arrays.asList(or).stream().distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(need)) {
            return;
        }
        List<Object> loginRoles = LoginContextHolder.getLoginRoles().stream().distinct().collect(Collectors.toList());
        loginRoles.retainAll(need);
        if (loginRoles.size() <= 0) {
            log.warn(msg1, need);
            throw new RuntimeException(msg);
        }
    }

    private void checkAuthAnd(String[] and1) {
        List<String> need = Arrays.asList(and1).stream().distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(need)) {
            return;
        }

        List<Object> loginAuths = LoginContextHolder.getLoginAuths().stream().distinct().collect(Collectors.toList());
        loginAuths.retainAll(need);

        if (loginAuths.size() != need.size()) {
            log.warn(msg4, need);
            throw new RuntimeException(msg);
        }
    }

    private void checkRoleAnd(String[] and) {
        List<String> need = Arrays.asList(and).stream().distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(need)) {
            return;
        }

        List<Object> loginRoles = LoginContextHolder.getLoginRoles().stream().distinct().collect(Collectors.toList());
        loginRoles.retainAll(need);

        if (loginRoles.size() != need.size()) {
            log.warn(msg2, need);
            throw new RuntimeException(msg);
        }
    }
}
